import numpy as np
import matplotlib.pyplot as plt



def load(fileName):  # 定义函数读取文件，输入为文件的路径：C:\Users\Junjie Wang\Desktop\机器学习\01.txt
    dataMat = [] 
    fr = open(fileName)#打开文件
    for line in fr.readlines():  # 返回list，list每个元素是每一行的字符串
        curLine = line.strip().split('\t')  # 删除line字符串中的空格，按\t进行分割。
        curLine = str.strip("\t")#删除字符串中的\t，否则下面无法利用map函数将字符串类型转化为浮点型
        fltLine = list(map(float, curLine))  # map函数将curline的元素转成float类型，并用list函数将其转化为列表格式
        dataMat.append(fltLine)  # 在datamat中添加新的fltline列表
    return np.array(dataMat)  # 返回一个矩阵。


def distEclud(vecA, vecB):#定义函数求两个向量之间的距离
    return np.sqrt(np.sum(np.power(vecA - vecB, 2)))  



def randCent(dataSet, k):# 构建聚簇中心，取k个随机质心
    centroid = np.array(np.zeros((k, 2)))  # 每个质心有2个坐标值，总共要k个质心
    for j in range(2):
        minj = min(dataSet[:,j])  # 最小值
        maxj = max(dataSet[:,j])  # 最大值
        rangej = float(maxj - minj)  # 得到当前列的范围
        centroid[:, j] = mat(minj + rangej * np.random.rand(k))# 在最小值和最大值之间取值
       
    return centroid  # 返回包含K个随机质心（centroid）的集合

    
def kMeans(dataSet, k, distMeans=distEclud, createCent=randCent):
        # 输入：数据集，k个质心,计算向量间距离的函数名，随机生成k个随机质心的函数名
        # 输出：包含质心的集合，簇分配结果矩阵
    m = dataSet.shape[0];counts = []  # 数据集的行数
    clusterAssments = [];
    centroids = []
    clusterAssment = np.array(np.zeros((m, 2)))  # 存放该样本属于哪类及质心距离
        
    centroid = createCent(dataSet, k)  # 先随机生成k个随机质心的集合
    clusterChanged = True  # 用来判断聚类是否已经收敛
    while clusterChanged:  # 当任意一个点的簇分配结果改变时，把每一个数据点划分到离它最近的中心点
        clusterChanged = False
        count = 0
        for i in range(m): 
            minDist = np.inf;minIndex = -1;
            for j in range(k):  # 对于每一质心，求出数据与质心间的距离
                distJI = distMeans(centroid[j, :], dataSet[i, :-1]) 
                if distJI < minDist:  # 更新最小值，如果第i个数据点到第j个中心点更近，则将i归属为j
                    minDist = distJI;minIndex = j 
            if clusterAssment[i, 0] != minIndex:  # 若该点的簇分配结果改变，则需要继续迭代
                clusterChanged = True;count += 1 
                    # print(clusterAssment[i,0],'-->',minIndex)
            clusterAssment[i, :] = minIndex, minDist ** 2  # 将第i个数据点的分配情况存入字典

        for cent in range(k):  # 重新计算中心点 
            ptsInClust = dataSet[clusterAssment[:, 0] == cent][:, :-1]  # 去第一列等于cent的所有列
            centroid[cent, :] = np.mean(ptsInClust, axis=0)  # 算出这些数据的中心点
               

           
        if clusterChanged == True:
            centroids.append(copy.copy(centroid))
            clusterAssments.append(copy.copy(clusterAssment))
            counts.append(count)
    return centroids, clusterAssments, counts

    
dat = load(r'C:\Users\Junjie Wang\Desktop\机器学习\01.txt')#给load函数输入地址，返回一个矩阵
myCentroids, clustAssings,counts = kMeans(dat, 2)
print(myCentroids)
t = len(clustAssings)
print(t)
print(counts)
fig1 = plt.figure(1, figsize=(15, 20))  # 进行绘图
    
for i in range(4):
    ax = fig1.add_subplot(32 * 10 + i + 1)
    s = clustAssings[i][:, 0] + 30
    c = clustAssings[i][:, 0] + 20
    ax.scatter(datMat[:, 0], datMat[:, 1], s, c)
    ax.scatter(myCentroids[i][:, 0], myCentroids[i][:, 1], s=150, c='r', marker='+')

plt.show()

